home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / processes / mp threaded sort / window.cp < prev    next >
Encoding:
Text File  |  2000-09-28  |  24.5 KB  |  985 lines

  1. /*
  2.     File:        Window.cp
  3.  
  4.     Contains:    Implementation of TWindow, a base class which provides a
  5.                 framework for building way-cool windows which even John
  6.                 Sullivan would be happy with. Floating windows and “smart
  7.                 zooming” algorithms are based on code samples provided by
  8.                 Dean Yu. Tim Craycroft, the guy making the window manager
  9.                 do all this work for you has also been a great help.
  10.  
  11.     Written by: Dave Falkenburg    
  12.  
  13.     Copyright:    Copyright © 1993-1999 by Apple Computer, Inc., All Rights Reserved.
  14.  
  15.                 You may incorporate this Apple sample source code into your program(s) without
  16.                 restriction. This Apple sample source code has been provided "AS IS" and the
  17.                 responsibility for its operation is yours. You are not permitted to redistribute
  18.                 this Apple sample source code as "Apple sample source code" after having made
  19.                 changes. If you're going to re-distribute the source, we require that you make
  20.                 it clear in the source that the code was descended from Apple sample source
  21.                 code, but that you've made changes.
  22.  
  23.     Change History (most recent first):
  24.                 7/27/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  25.                 11/17/94    DRF                Add casts for CFront & PPCC. Also dealt with the change to
  26.                                             ClipAbove in the latest universal headers.
  27.                 11/12/94    DRF                Added AdjustMenusBeforeMenuSelection.
  28.                   11/8/94    DRF                Add some better menu handling methods.
  29.                  9/27/94    DRF                 AppLib.h is now Sprocket.h
  30.                   9/9/94    DRF                Reorganized headers and removed redundant #includes.
  31.                   9/4/94    DRF                Added DrawJustTheGrowIcon.
  32.                  8/27/94    DRF                In TWindow::Close, call window’s (de)Activate method before
  33.                                             closing so that menus can be properly updated.
  34.     To Do:        Make sure invisible windows can be created & managed
  35.                 Handle modal windows as another class of windows
  36.                 Fix activate bugs when showing and hiding windows
  37.                 Window positioning methods (getters and setters)
  38.                 Display Manager support
  39.                 Changes to support AEObject model
  40. */
  41. #include "Sprocket.h"
  42. #include "Window.h"
  43.  
  44. #include <Script.h>        //    for GetMBarHeight()
  45. #include <LowMem.h>        //    for LMGetWindowList()
  46.  
  47.  
  48. const short            kFloatingWindowKind        = 1000;
  49. const short            kNormalWindowKind        = 1001;
  50. const WindowPtr     kNoFloatingWindows        = (WindowPtr) -1;
  51.  
  52. const short            kScreenEdgeSlop            = 4;
  53. const short            kSpaceForFinderIcons    = 64;
  54. const short            kMinimumTitleBarHeight    = 21;
  55. const short            kMinimumWindowSize        = 32;
  56.  
  57. static void            HiliteShowHideFloatingWindows(Boolean hiliting,Boolean hiding);
  58.  
  59. static void            FindScreenRectWithLargestPartOfWindow(WindowPtr aWindow,Rect *theBestScreenRect, GDHandle * theBestDevice);
  60. static pascal void    CalculateWindowAreaOnDevice(short depth,short deviceFlags,GDHandle targetDevice,long userData);
  61.  
  62.  
  63. struct    CalcWindowAreaDeviceLoopUserData
  64.     {
  65.     GDHandle    fScreenWithLargestPartOfWindow;
  66.     long        fLargestArea;
  67.     Rect        fWindowBounds;
  68.     };
  69.  
  70.  
  71.  
  72.  
  73.  
  74. TWindow::TWindow()
  75.     {
  76.     }
  77.  
  78.  
  79. TWindow::~TWindow()
  80.     {
  81.     }
  82.  
  83.  
  84. void
  85. TWindow::CreateWindow(WindowType typeOfWindowToCreate /* = kNormalWindow */)
  86.     {
  87.     WindowPtr    behindWindow,oldFrontMostWindow;
  88.     
  89.     if (typeOfWindowToCreate == kModalWindow)
  90.         {
  91.         DebugStr((StringPtr) "\pModal windows aren’t supported yet");
  92.         fWindowType = kFloatingWindow;
  93.         return;
  94.         }
  95.     else if (typeOfWindowToCreate == kFloatingWindow)
  96.         {
  97.         behindWindow = (WindowPtr) -1;
  98.         oldFrontMostWindow = FrontWindow();
  99.  
  100.         fWindowType = kFloatingWindow;
  101.         }
  102.     else if (typeOfWindowToCreate == kNormalWindow)
  103.         {
  104.         behindWindow = LastFloatingWindow();
  105.  
  106.         fWindowType = kNormalWindow;
  107.         
  108.         if (behindWindow == kNoFloatingWindows)
  109.             oldFrontMostWindow = nil;
  110.         else
  111.             oldFrontMostWindow = (WindowPtr) ((WindowPeek) behindWindow)->nextWindow;
  112.         }
  113.  
  114.     fWindow = this->MakeNewWindow(behindWindow);
  115.     fIsVisible = ((WindowPeek) fWindow)->visible;
  116.  
  117.     if (fWindow)
  118.         {
  119.         SetWRefCon(fWindow,(long) this);
  120.  
  121.         if (typeOfWindowToCreate == kModalWindow)
  122.             {
  123.             DebugStr((StringPtr) "\pCan’t create Modal windows yet");
  124.             }
  125.         else if (typeOfWindowToCreate == kFloatingWindow)
  126.             {
  127.             ((WindowPeek) fWindow)->windowKind = kFloatingWindowKind;
  128.             
  129.             //    make sure the other window stays hilited
  130.             if (oldFrontMostWindow)
  131.                 HiliteAndActivateWindow(oldFrontMostWindow,true);
  132.             }
  133.         else if (typeOfWindowToCreate == kNormalWindow)
  134.             {
  135.             ((WindowPeek) fWindow)->windowKind = kNormalWindowKind;
  136.  
  137.             //    unhighlight the old front window
  138.             if (oldFrontMostWindow)
  139.                 HiliteAndActivateWindow(oldFrontMostWindow,false);
  140.  
  141.             //    hilite the new window…
  142.             HiliteAndActivateWindow(fWindow,true);
  143.             }
  144.         }
  145.     }
  146.  
  147.  
  148. void
  149. TWindow::AdjustCursor(EventRecord * /* anEvent */)
  150.     {
  151.     }
  152.  
  153. void
  154. TWindow::Idle(EventRecord * /* anEvent */)
  155.     {
  156.     }
  157.     
  158. void
  159. TWindow::Activate(Boolean /* activating */)
  160.     {
  161.     }
  162.     
  163. void
  164. TWindow::Draw(void)
  165.     {
  166.     }
  167.     
  168. void
  169. TWindow::Click(EventRecord * /* anEvent */)
  170.     {
  171.     }
  172.     
  173. void
  174. TWindow::KeyDown(EventRecord * /* anEvent */)
  175.     {
  176.     }
  177.  
  178.  
  179. void
  180. TWindow::Select(void)
  181.     {
  182.     WindowPtr    currentFrontWindow;
  183.     
  184.     if (fWindowType == kFloatingWindow)
  185.         currentFrontWindow = FrontWindow();
  186.     else if (fWindowType == kNormalWindow)
  187.         currentFrontWindow = MyFrontNonFloatingWindow();
  188.     else
  189.         {
  190.         }
  191.  
  192.     if (currentFrontWindow != fWindow)
  193.         {
  194.         if (fWindowType == kFloatingWindow)
  195.             BringToFront(fWindow);
  196.         else
  197.             {
  198.             WindowPtr    lastFloater = LastFloatingWindow();
  199.  
  200.             //    If there are no floating windows,
  201.             //    just call SelectWindow like the good ol’ days
  202.  
  203.             if (lastFloater == kNoFloatingWindows)
  204.                 SelectWindow(fWindow);
  205.             else
  206.                 {
  207.                 // Deactivate the window currently in front.
  208.  
  209.                 HiliteAndActivateWindow(currentFrontWindow,false);
  210.     
  211.                 // Bring it behind the last floating window and activate it.
  212.                 // Note that Inside Mac 1 states that you need to call PaintOne() and CalcVis() on a
  213.                 // window if you are using SendBehind() to bring it closer to the front.  With System 7,
  214.                 // this is no longer necessary.
  215.  
  216.                 SendBehind(fWindow,lastFloater);
  217.                 HiliteAndActivateWindow(fWindow,true);
  218.                 }
  219.             }
  220.         }
  221.     }
  222.  
  223.  
  224. void
  225. TWindow::Drag(Point startPoint)
  226.     {
  227.     GrafPtr        savePort;
  228.     KeyMap        theKeyMap;
  229.     Boolean        commandKeyDown = false;
  230.     RgnHandle    draggingRegion;
  231.     long        dragResult;
  232.     WindowPeek    windowAsWindowPeek = (WindowPeek) fWindow;
  233.     Boolean     gLiveDrag;
  234.     
  235.     
  236.     if (WaitMouseUp())        //    de-bounce?
  237.         {
  238.         // Set up the Window Manager port.
  239.     
  240.         GetPort(&savePort);
  241.         SetPort(gWindowManagerPort);
  242.         SetClip(GetGrayRgn());
  243.  
  244.         // Check to see if the command key is down.
  245.     
  246.         GetKeys(theKeyMap);
  247.         commandKeyDown = ((theKeyMap[1] & 0x8000) != 0);
  248.         gLiveDrag = (theKeyMap[1] >> 2) & 0x01 ;
  249.         
  250.         if (commandKeyDown)
  251.             {
  252.             //    We’re not going to change window ordering,
  253.             //    so make sure that we don’t drag in front of
  254.             //    other windows which may be in front of ours.
  255.  
  256. //    11/16/94    <Windows.h> on ETO defines this routine to take
  257. //                a WindowPtr instead of a WindowPeek. When building
  258. //                with new headers (like those included with ETO 16)
  259. //                make sure to define USEOLDUNIVERSALHEADERS to 0.
  260.  
  261. #if    USEOLDUNIVERSALHEADERS
  262.             ClipAbove(windowAsWindowPeek);
  263. #else
  264.             ClipAbove((WindowPtr) windowAsWindowPeek);
  265. #endif
  266.             }
  267.         else if (fWindowType != kFloatingWindow)
  268.             {
  269.             //    We’re dragging a normal window, so make sure
  270.             //    that we don’t drag in front of any floating
  271.             //    windows.
  272.  
  273. //    11/16/94    <Windows.h> on ETO defines this routine to take
  274. //                a WindowPtr instead of a WindowPeek. When building
  275. //                with new headers (like those included with ETO 16)
  276. //                make sure to define USEOLDUNIVERSALHEADERS to 0.
  277.  
  278. #if    USEOLDUNIVERSALHEADERS
  279.             ClipAbove((WindowPeek) MyFrontNonFloatingWindow());
  280. #else
  281.             ClipAbove(MyFrontNonFloatingWindow());
  282. #endif
  283.             }
  284.         
  285.         //    Drag an outline of the window around the desktop.
  286.         //    NOTE: DragGrayRgn destroys the region passed in, so make a copy
  287.  
  288.         //if (gLiveDrag) {
  289.             /*Rect r = {0,0,0,0};
  290.             Point origin = {0,0};    
  291.             Point diff;
  292.             EventRecord event;
  293.             GrafPtr tempPort;
  294.             
  295.             
  296.             GetPort(&tempPort);
  297.             SetPort(fWindow);    
  298.             (void)OSEventAvail(everyEvent,&event);
  299.             
  300.             LocalToGlobal(&origin);
  301.             diff.h = ( origin.h - event.where.h);
  302.             diff.v = ( origin.v -event.where.v);
  303.             //origin.h = windowAsWindowPeek->strucRgn[0]->rgnBBox.left;
  304.             //origin.v = windowAsWindowPeek->strucRgn[0]->rgnBBox.top;
  305.             SetPort(tempPort);
  306.             while (StillDown()) {
  307.                 EventRecord event;
  308.                 //short slop;
  309.                 
  310.                 //(void)OSEventAvail(everyEvent,&event);
  311.                 
  312.                 //ValidRect(&goodRect_Rect);
  313.                 (void)WaitNextEvent(everyEvent,&event,1,nil);
  314.                 
  315.                 if (event.what == updateEvt) {
  316.                     WindowRef window = (WindowRef)event.message;
  317.                     
  318.                     
  319.                     if (window) {
  320.                         TWindow * wobj;
  321.                         
  322.                         SetPort(window);
  323.                         BeginUpdate(window);
  324.                         wobj = GetWindowObject(window);
  325.  
  326.                         wobj->Draw();
  327.                         EndUpdate(window);
  328.                         SetPort(tempPort);
  329.                     }
  330.                     
  331.                     
  332.                 }
  333.                 
  334.                 event.where.h += diff.h ;
  335.                 event.where.v += diff.v;
  336.                 
  337.  
  338.                 
  339.                 
  340.                 if (coplandTask)
  341.                 MoveWindow(fWindow,event.where.h,event.where.v,true);
  342.  
  343.                 Idle(nil);
  344.                 
  345.                 dragResult = 0;
  346.                 
  347.             }
  348.             */
  349.         //} else {
  350.             draggingRegion = NewRgn();
  351.             CopyRgn(windowAsWindowPeek->strucRgn,draggingRegion);
  352.             dragResult = DragGrayRgn(draggingRegion, startPoint, &gDeskRectangle, &gDeskRectangle, noConstraint, nil);
  353.             DisposeRgn(draggingRegion);
  354.  
  355.         //}
  356.         SetPort(savePort);    //    Get back to old port
  357.  
  358.         if ((dragResult != 0) && (dragResult != 0x80008000))
  359.             {
  360.             this->Nudge((short) (dragResult & 0xFFFF),(short) (dragResult >> 16));
  361.             }
  362.         }
  363.  
  364.     if (!commandKeyDown)
  365.         Select();
  366.     }
  367.  
  368. void
  369. TWindow::Nudge(short horizontalDistance, short verticalDistance)
  370.     {
  371.     WindowPeek    windowAsWindowPeek = (WindowPeek) fWindow;
  372.     short        newHorizontalPosition,newVerticalPosition;
  373.     
  374.     newHorizontalPosition = (short) (**windowAsWindowPeek->contRgn).rgnBBox.left + horizontalDistance;
  375.     newVerticalPosition = (short) (**windowAsWindowPeek->contRgn).rgnBBox.top + verticalDistance;
  376.  
  377.     MoveWindow(fWindow,newHorizontalPosition,newVerticalPosition,false);
  378.     }
  379.  
  380. void
  381. TWindow::Grow(Point startPoint)
  382.     {
  383.     GrafPtr    oldPort;
  384.     long    newSize;
  385.     Rect    oldWindowRect,resizeLimits;
  386.     
  387.     GetPort(&oldPort);
  388.     
  389.     GetWindowSizeLimits(&resizeLimits);
  390.     newSize = GrowWindow(fWindow,startPoint,&resizeLimits);
  391.     if (newSize)
  392.         {
  393.         oldWindowRect = fWindow->portRect;
  394.         SizeWindow(fWindow,(short) newSize,(short) (newSize >> 16),true);
  395.         SetPort(fWindow);
  396.         this->AdjustForNewWindowSize(&oldWindowRect,&fWindow->portRect);
  397.         }
  398.     
  399.     SetPort(oldPort);
  400.     }
  401.  
  402.  
  403. void
  404. TWindow::Zoom(short zoomState)
  405.     {
  406.     GrafPtr        oldPort;
  407.     FontInfo    systemFontInfo;
  408.     short        titleBarHeight;
  409.     Rect        bestScreenRect,perfectWindowRect,scratchRect;
  410.     short        amountOffscreen;
  411.     WindowPeek    windowAsWindowPeek = (WindowPeek) fWindow;
  412.     GDHandle    bestDevice;
  413.     
  414.     GetPort(&oldPort);
  415.  
  416.     //    Figure out the height of the title bar so we can properly position
  417.     //    a window. The algorithm is stolen from the System 7.x 'WDEF' (0)
  418.     //
  419.     //    This probably isn’t the best thing to do: A better way might be 
  420.     //    to diff the structure and content region rectangles?
  421.  
  422.     SetPort(gWindowManagerPort);
  423.     GetFontInfo(&systemFontInfo);
  424.     titleBarHeight = (short) (systemFontInfo.ascent + systemFontInfo.descent + 4);
  425.     if ((titleBarHeight % 2) == 1)
  426.         titleBarHeight--;
  427.     if (titleBarHeight < kMinimumTitleBarHeight)
  428.         titleBarHeight = kMinimumTitleBarHeight;
  429.  
  430.  
  431.     //    Only do the voodoo magic if we are really “zooming” the window.
  432.  
  433.     if (zoomState == inZoomOut)
  434.         {
  435.         FindScreenRectWithLargestPartOfWindow(fWindow,&bestScreenRect,&bestDevice);
  436.         bestScreenRect.top += titleBarHeight;
  437.  
  438.         this->GetPerfectWindowSize(&perfectWindowRect);
  439.         OffsetRect(&perfectWindowRect,-perfectWindowRect.left,-perfectWindowRect.top);
  440.  
  441.         //    Take the zero-pined perfect window size and move it to
  442.         //    the top left of the    window’s content region.
  443.  
  444.         OffsetRect(&perfectWindowRect,(**windowAsWindowPeek->contRgn).rgnBBox.left,
  445.                                       (**windowAsWindowPeek->contRgn).rgnBBox.top);
  446.  
  447.         
  448.         //    Does perfectWindowRect fit completely on the best screen?
  449.         
  450.         SectRect(&perfectWindowRect, &bestScreenRect, &scratchRect);
  451.         if (!EqualRect(&perfectWindowRect, &scratchRect))
  452.             {
  453.             //    SectRect sez perfectWindowRect doesn’t completely fit
  454.             //    on the screen, so bump the window so that more of it fits.
  455.  
  456.             //    Make sure that the left edge of perfectWindowRect is forced
  457.             //    onto the best screen.  This is in case we are bumping
  458.             //    the window to the right.
  459.  
  460.             amountOffscreen = bestScreenRect.left - perfectWindowRect.left;
  461.             if (amountOffscreen > 0)
  462.                 {
  463.                 perfectWindowRect.left += amountOffscreen;
  464.                 perfectWindowRect.right += amountOffscreen;
  465.                 }
  466.  
  467.             //    Make sure that the left edge of perfectWindowRect is forced
  468.             //    onto the best screen.  This is in case we are bumping
  469.             //    the window downward to a new screen.
  470.     
  471.             amountOffscreen = bestScreenRect.top - perfectWindowRect.top;
  472.             if (amountOffscreen > 0)
  473.                 {
  474.                 perfectWindowRect.top += amountOffscreen;
  475.                 perfectWindowRect.bottom += amountOffscreen;
  476.                 }
  477.  
  478.             //    If right edge of window falls off the screen,
  479.             //        Move window to the left until the right edge IS on the screen
  480.             //        OR the left edge is at bestScreenRect.left
  481.  
  482.             amountOffscreen = perfectWindowRect.right - bestScreenRect.right;
  483.             if (amountOffscreen > 0)
  484.                 {
  485.                 //    Are we going to push the left edge offscreen? If so, change the
  486.                 //    offset so we move the window all the way over to the left.
  487.                 
  488.                 if ((perfectWindowRect.left - amountOffscreen) < bestScreenRect.left)
  489.                     amountOffscreen = perfectWindowRect.left - bestScreenRect.left;
  490.  
  491.                 perfectWindowRect.left -= amountOffscreen;
  492.                 perfectWindowRect.right -= amountOffscreen;
  493.                 }
  494.  
  495.             //    If bottom edge of window falls off the screen,
  496.             //        Move window to up until the bottom edge IS on the screen
  497.             //        OR the top edge is at bestScreenRect.top
  498.  
  499.             amountOffscreen = perfectWindowRect.bottom - bestScreenRect.bottom;
  500.             if (amountOffscreen > 0)
  501.                 {
  502.                 //    Are we going to push the top edge offscreen? If so, change the
  503.                 //    offset so we move the window just to the top.
  504.                 
  505.                 if ((perfectWindowRect.top - amountOffscreen) < bestScreenRect.top)
  506.                     amountOffscreen = perfectWindowRect.top - bestScreenRect.top;
  507.  
  508.                 perfectWindowRect.top -= amountOffscreen;
  509.                 perfectWindowRect.bottom -= amountOffscreen;
  510.                 }
  511.  
  512.             SectRect(&perfectWindowRect, &bestScreenRect, &scratchRect);
  513.             if (!EqualRect(&perfectWindowRect, &scratchRect))
  514.                 {
  515.                 //    The edges of the window still fall offscreen,
  516.                 //    so make the window smaller until it fits.
  517.                 
  518.                 if (perfectWindowRect.bottom > bestScreenRect.bottom)
  519.                     perfectWindowRect.bottom = bestScreenRect.bottom;
  520.  
  521.                 //    If the right edge is still falling off,
  522.                 //        save space for Finder’s disk icons as well.
  523.  
  524.                 if (perfectWindowRect.right > bestScreenRect.right)
  525.                     {
  526.                     perfectWindowRect.right = bestScreenRect.right;
  527.                     
  528.                     //    If we were on the main screen, leave room for Finder icons, too.
  529.                     
  530.                     if (bestDevice == GetMainDevice())
  531.                         perfectWindowRect.right -= kSpaceForFinderIcons;
  532.                     }
  533.                 }
  534.             }
  535.  
  536.         //    Stash our new rectangle inside of the Window’s dataHandle
  537.         //    so that ZoomWindow does the right thing.
  538.         
  539.         (**((WStateDataHandle) (windowAsWindowPeek->dataHandle))).stdState = perfectWindowRect;
  540.         }
  541.  
  542.     //    HEY YOU! Don’t forget to set the port to the window being zoomed
  543.     //    Why, you ask? Because IM-IV-50 says to; otherwise you die
  544.     
  545.     SetPort(fWindow);
  546.  
  547.     Rect    oldWindowRect = fWindow->portRect;
  548.     
  549.     ZoomWindow(fWindow,zoomState,false);
  550.     this->AdjustForNewWindowSize(&oldWindowRect,&fWindow->portRect);
  551.  
  552.     SetPort(oldPort);
  553.     }
  554.  
  555. void
  556. TWindow::ShowHide(Boolean showFlag)
  557.     {
  558.     //    Here we need the “::” in front of ShowHide to indicate we are calling
  559.     //    the global function, and not the method ShowHide. Unintended recursion
  560.     //    can do bad things to the unsuspecting programmer.
  561.     
  562.     //    Some C++ programmers would always prepend the “::” on function calls.
  563.     
  564.     ::ShowHide(fWindow,showFlag);
  565.     fIsVisible = showFlag;
  566.     }
  567.     
  568.  
  569. Boolean
  570. TWindow::EventFilter(EventRecord * /* theEvent */)
  571.     {
  572.     return false;
  573.     }
  574.     
  575.  
  576. void
  577. TWindow::GetPerfectWindowSize(Rect *perfectSize)
  578.     {
  579.     *perfectSize = qd.screenBits.bounds;
  580.     }
  581.  
  582. void
  583. TWindow::GetWindowSizeLimits(Rect *limits)
  584.     {
  585.     limits->top = limits->left = kMinimumWindowSize;
  586.     limits->right = gDeskRectangle.right - gDeskRectangle.left;
  587.     limits->bottom = gDeskRectangle.bottom - gDeskRectangle.top;
  588.     }
  589.  
  590. void
  591. TWindow::AdjustForNewWindowSize(Rect * /* oldRect */, Rect * /* newSize */)
  592.     {
  593.     }
  594.  
  595.  
  596. Boolean
  597. TWindow::IsVisible(void)
  598.     {
  599.     return fIsVisible;
  600.     }
  601.  
  602.  
  603. Boolean
  604. TWindow::CanClose(void)
  605.     {
  606.     return true;
  607.     }
  608.  
  609.  
  610. Boolean
  611. TWindow::Close(void)
  612.     {
  613.     WindowPtr    newFrontWindow = nil;
  614.     
  615.     if (MyFrontNonFloatingWindow() == fWindow)
  616.         newFrontWindow = (WindowPtr) ((WindowPeek) fWindow)->nextWindow;
  617.  
  618.     this->Activate(false);
  619.     DisposeWindow(fWindow);
  620.  
  621.     if (newFrontWindow)
  622.         HiliteAndActivateWindow(newFrontWindow,true);
  623.  
  624.     return true;
  625.     }
  626.  
  627.  
  628. Boolean
  629. TWindow::DeleteAfterClose(void)
  630.     {
  631.     return true;
  632.     }
  633.  
  634.  
  635. void
  636. TWindow::AdjustMenusBeforeMenuSelection(void)
  637.     {
  638.     }
  639.  
  640.     
  641. void
  642. TWindow::DoMenuSelection(short /* menu */, short /* item */)
  643.     {
  644.     }
  645.     
  646.  
  647. void
  648. TWindow::DoMenuCommand(unsigned long /* menuCommand */)
  649.     {
  650.     }
  651.  
  652.  
  653. OSErr
  654. TWindow::HandleDrag(DragTrackingMessage dragMessage,DragReference theDrag)
  655.     {
  656.     OSErr    result = dragNotAcceptedErr;
  657.     
  658.     switch (dragMessage)
  659.         {
  660.         case    kDragTrackingEnterWindow:
  661.             result = this->DragEnterWindow(theDrag);
  662.             break;
  663.         
  664.         case    kDragTrackingInWindow:
  665.             result = this->DragInWindow(theDrag);
  666.             break;
  667.             
  668.         case    kDragTrackingLeaveWindow:
  669.             result = this->DragLeaveWindow(theDrag);
  670.             break;
  671.             
  672.         default:
  673.             break;
  674.         }
  675.  
  676.     return result;
  677.     }
  678.  
  679.  
  680. OSErr
  681. TWindow::DragEnterWindow(DragReference /* theDrag */)
  682.     {
  683.     return dragNotAcceptedErr;
  684.     }
  685.  
  686.  
  687. OSErr
  688. TWindow::DragInWindow(DragReference /* theDrag */)
  689.     {
  690.     return dragNotAcceptedErr;
  691.     }
  692.  
  693.  
  694. OSErr
  695. TWindow::DragLeaveWindow(DragReference /* theDrag */)
  696.     {
  697.     return dragNotAcceptedErr;
  698.     }
  699.     
  700.  
  701. OSErr
  702. TWindow::HandleDrop(DragReference /* theDrag */)
  703.     {
  704.     return dragNotAcceptedErr;
  705.     }
  706.  
  707.  
  708. ///////////////////////////////////////////////////////////////////////////
  709. //
  710. //    Utility Functions used for floating windows
  711. //
  712.  
  713. TWindow *
  714. GetWindowObject(WindowPtr aWindow)
  715.     {
  716.     short    wKind;
  717.     
  718.     if (aWindow != nil)
  719.         {
  720.         wKind = ((WindowPeek) aWindow)->windowKind;
  721.  
  722.         if (wKind >= userKind)
  723.             {
  724.             //    All windowKinds >= userKind are based upon TWindow
  725.  
  726.             return (TWindow *) GetWRefCon(aWindow);
  727.             }
  728.         }
  729.     return (TWindow *) nil;
  730.     }
  731.  
  732.  
  733. ////////////////////////////////////////////////////////////////////////
  734. //
  735. //    Utility functions
  736.  
  737.  
  738. pascal WindowPtr
  739. GetNewColorOrBlackAndWhiteWindow(short windowID, void *wStorage, WindowPtr behind)
  740.     {
  741.     if (gHasColorQuickdraw)
  742.         return GetNewCWindow(windowID,wStorage,behind);
  743.     else
  744.         return GetNewWindow(windowID,wStorage,behind);
  745.     }
  746.  
  747.  
  748. pascal WindowPtr
  749. NewColorOrBlackAndWhiteWindow(void *wStorage, const Rect *boundsRect, ConstStr255Param title, Boolean visible, short theProc, WindowPtr behind, Boolean goAwayFlag, long refCon)
  750.     {
  751.     if (gHasColorQuickdraw)
  752.         return NewCWindow(wStorage,boundsRect,title,visible,theProc,behind,goAwayFlag,refCon);
  753.     else
  754.         return NewWindow(wStorage,boundsRect,title,visible,theProc,behind,goAwayFlag,refCon);
  755.     }
  756.  
  757.  
  758. void
  759. DrawJustTheGrowIcon(WindowPtr aWindow)
  760.     {
  761.     GrafPtr        savedPort;
  762.     RgnHandle    savedClip = NewRgn();
  763.     Rect        growBoxRect;
  764.     
  765.     GetPort(&savedPort);
  766.     SetPort(aWindow);
  767.     GetClip(savedClip);
  768.  
  769.     //    clip to just the bottom right corner of the window
  770.     
  771.     growBoxRect.top = aWindow->portRect.bottom - kScrollbarWidth;
  772.     growBoxRect.bottom = aWindow->portRect.bottom;
  773.     growBoxRect.left = aWindow->portRect.right - kScrollbarWidth;
  774.     growBoxRect.right = aWindow->portRect.right;
  775.     ClipRect(&growBoxRect);
  776.  
  777.     DrawGrowIcon(aWindow);
  778.  
  779.     SetClip(savedClip);
  780.     DisposeRgn(savedClip);    
  781.  
  782.     SetPort(savedPort);
  783.     }
  784.     
  785.  
  786. WindowPtr
  787. LastFloatingWindow(void)
  788.     {
  789.     WindowPeek    aWindow = (WindowPeek) FrontWindow();
  790.     WindowPtr    lastFloater = (WindowPtr) kNoFloatingWindows;
  791.     
  792.     while (aWindow && (aWindow->windowKind == kFloatingWindowKind))
  793.         {
  794.         if (aWindow->visible)
  795.             lastFloater = (WindowPtr) aWindow;
  796.  
  797.         aWindow = (WindowPeek) aWindow->nextWindow;
  798.         }
  799.     return(lastFloater);
  800.     }
  801.  
  802.  
  803.  
  804. WindowPtr
  805. MyFrontNonFloatingWindow(void)
  806.     {
  807.     WindowPeek    aWindow = (WindowPeek) LMGetWindowList();
  808.  
  809.     //    Skip over floating windows
  810.         
  811.     while (aWindow && (aWindow->windowKind == kFloatingWindowKind))
  812.         aWindow = (WindowPeek) aWindow->nextWindow;
  813.  
  814.     //    Skip over invisible, but otherwise normal windows
  815.     
  816.     while (aWindow && (aWindow->visible == 0))
  817.         aWindow = (WindowPeek) aWindow->nextWindow;
  818.         
  819.     return (WindowPtr) aWindow;
  820.     }
  821.  
  822. void
  823. HiliteAndActivateWindow(WindowPtr aWindow,Boolean active)
  824.     {
  825.     GrafPtr        oldPort;
  826.     TWindow    *    wobj = GetWindowObject(aWindow);
  827.     
  828.     if (aWindow)
  829.         {
  830.         HiliteWindow(aWindow,active);
  831.  
  832.         if (wobj != nil)
  833.             {
  834.             GetPort(&oldPort);
  835.             SetPort(aWindow);
  836.             wobj->Activate(active);
  837.             SetPort(oldPort);
  838.             }    
  839.         }
  840.     }
  841.  
  842. void
  843. SuspendResumeWindows(Boolean resuming)
  844.     {
  845.     //    When we suspend/resume, hide/show all the visible floaters
  846.     
  847.     HiliteShowHideFloatingWindows(resuming,true);
  848.     }
  849.  
  850. void
  851. HiliteWindowsForModalDialog(Boolean hiliting)
  852.     {
  853.     //    When we display a modal dialog, we need to unhighlight
  854.     //    all visible floaters. We also need to re-hilite them
  855.     //    afterwards.
  856.     
  857.     HiliteShowHideFloatingWindows(hiliting,false);
  858.     }
  859.  
  860. void
  861. HiliteShowHideFloatingWindows(Boolean hiliting,Boolean dohiding)
  862.     {
  863.     WindowPeek    aWindow;
  864.     TWindow *    wobj;
  865.     
  866.     HiliteAndActivateWindow(MyFrontNonFloatingWindow(),hiliting);
  867.  
  868.     aWindow = (WindowPeek) LMGetWindowList();
  869.     while (aWindow && aWindow->windowKind == kFloatingWindowKind)
  870.         {
  871.         wobj = GetWindowObject((WindowPtr) aWindow);
  872.         
  873.         //    If we are hiding or showing, only hide/show windows
  874.         //    that were visible to begin with.
  875.         
  876.         //    NOTE:    We use our copy of the visible flag so we can
  877.         //            automatically show floaters on a resume event.
  878.         
  879.         //    NOTE:    Since this isn’t a method of TWindow, we don’t
  880.         //            really need the “::” on ShowHide, but as long
  881.         //            as we’re trying to avoid ambiguity.
  882.         
  883.         if (dohiding && (wobj != nil) && (wobj->IsVisible()))
  884.             ::ShowHide((WindowPtr) aWindow,hiliting);
  885.             
  886.         //    All floaters are hilited if any floater is hilited
  887.  
  888.         HiliteWindow((WindowPtr) aWindow,hiliting);
  889.         aWindow = (WindowPeek) aWindow->nextWindow;
  890.         }
  891.     }
  892.  
  893.  
  894. ///////////////////////////////////////////////////////////////////////////
  895. //
  896. //    Routines used for dealing with windows and multiple screens
  897. //
  898.  
  899. pascal void
  900. CalculateWindowAreaOnDevice(short /* depth */,short /* deviceFlags */,GDHandle targetDevice,long userData)
  901.     {
  902.     CalcWindowAreaDeviceLoopUserData *    deviceLoopDataPtr;
  903.     long                                windowAreaOnThisScreen;
  904.     Rect                                windowRectOnThisScreen;
  905.     
  906.     deviceLoopDataPtr = (CalcWindowAreaDeviceLoopUserData *) userData;
  907.  
  908.     SectRect(&deviceLoopDataPtr->fWindowBounds, &(**targetDevice).gdRect,&windowRectOnThisScreen);
  909.     OffsetRect(&windowRectOnThisScreen,-windowRectOnThisScreen.left,-windowRectOnThisScreen.top);
  910.     windowAreaOnThisScreen = windowRectOnThisScreen.right * windowRectOnThisScreen.bottom;
  911.  
  912.     if (windowAreaOnThisScreen > deviceLoopDataPtr->fLargestArea)
  913.         {
  914.         deviceLoopDataPtr->fLargestArea = windowAreaOnThisScreen;
  915.         deviceLoopDataPtr->fScreenWithLargestPartOfWindow = targetDevice;
  916.         }
  917.     }
  918.  
  919.  
  920. DeviceLoopDrawingUPP CallCalcWindowAreaOnDevice = NewDeviceLoopDrawingProc(&CalculateWindowAreaOnDevice);
  921.  
  922.  
  923. void
  924. FindScreenRectWithLargestPartOfWindow(WindowPtr aWindow,Rect *theBestScreenRect,GDHandle * theBestDevice)
  925.     {
  926.     RgnHandle                            copyOfWindowStrucRgn;
  927.     CalcWindowAreaDeviceLoopUserData    deviceLoopData;
  928.  
  929.     //    Use DeviceLoop to find out what GDevice contains the largest
  930.     //    portion of the supplied window.
  931.     //
  932.     //    NOTE:    Assumes thePort == the Window Manager Port because we using
  933.     //            the window strucRgn, not contRgn.
  934.  
  935.     deviceLoopData.fScreenWithLargestPartOfWindow = nil;
  936.     deviceLoopData.fLargestArea = -1;
  937.     deviceLoopData.fWindowBounds = (**(((WindowPeek) aWindow)->contRgn)).rgnBBox;
  938.     
  939.     copyOfWindowStrucRgn = NewRgn();
  940.     CopyRgn(((WindowPeek) aWindow)->strucRgn,copyOfWindowStrucRgn);
  941.  
  942.     DeviceLoop(copyOfWindowStrucRgn,CallCalcWindowAreaOnDevice,(long) &deviceLoopData,singleDevices);    
  943.  
  944.     DisposeRgn(copyOfWindowStrucRgn);
  945.     
  946.     *theBestDevice = deviceLoopData.fScreenWithLargestPartOfWindow;
  947.     *theBestScreenRect = (**(deviceLoopData.fScreenWithLargestPartOfWindow)).gdRect;
  948.  
  949.     //    Leave some space around the edges of the screen so window look good, AND
  950.     //    if the best device is the main screen, leave space for the Menubar
  951.     
  952.     InsetRect(theBestScreenRect,kScreenEdgeSlop,kScreenEdgeSlop);
  953.     if (GetMainDevice() == deviceLoopData.fScreenWithLargestPartOfWindow)
  954.         theBestScreenRect->top += GetMBarHeight();
  955.     }
  956.  
  957.  
  958. ///////////////////////////////////////////////////////////////////////////
  959. //
  960. //    Drag Manager callback routines which dispatch to a window’s method
  961. //
  962.  
  963. pascal OSErr
  964. CallWindowDragTrackingHandler(DragTrackingMessage dragMessage,WindowPtr theWindow,void * /* refCon */,DragReference theDrag)
  965.     {
  966.     TWindow *wobj = GetWindowObject(theWindow);
  967.     
  968.     if (wobj)
  969.         return(wobj->HandleDrag(dragMessage,theDrag));
  970.     else
  971.         return dragNotAcceptedErr;
  972.     }
  973.  
  974.     
  975. pascal OSErr
  976. CallWindowDragReceiveHandler(WindowPtr theWindow,void * /* refCon */,DragReference theDrag)
  977.     {
  978.     TWindow *wobj = GetWindowObject(theWindow);
  979.     
  980.     if (wobj)
  981.         return(wobj->HandleDrop(theDrag));
  982.     else
  983.         return dragNotAcceptedErr;
  984.     }
  985.